package cn.iocoder.yudao.module.xkfz.service.reporting.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.xkfz.domain.emnu.RulesTypeEnum;
import cn.iocoder.yudao.module.xkfz.domain.entity.basic.IndicatorTree;
import cn.iocoder.yudao.module.xkfz.domain.entity.operationalPerformance.MetricDirectScore;
import cn.iocoder.yudao.module.xkfz.domain.entity.rules.RatioBandInfo;
import cn.iocoder.yudao.module.xkfz.domain.entity.rules.RulesTypeLevel;
import cn.iocoder.yudao.module.xkfz.domain.entity.rules.ScoreCalculationData;
import cn.iocoder.yudao.module.xkfz.domain.entity.rules.SortMethod;
import cn.iocoder.yudao.module.xkfz.mapper.basic.IndicatorTreeMapper;
import cn.iocoder.yudao.module.xkfz.mapper.operationalPerformance.MetricDirectScoreMapper;
import cn.iocoder.yudao.module.xkfz.mapper.rules.RatioBandInfoMapper;
import cn.iocoder.yudao.module.xkfz.mapper.rules.RulesTypeLevelMapper;
import cn.iocoder.yudao.module.xkfz.mapper.rules.SortMethodMapper;
import cn.iocoder.yudao.module.xkfz.service.reporting.ScoreCalculationService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 上报数据根据规则进行算分，并存入数据库的指标得分表
 * @Author ZWC
 * @Date 2024/4/28 15:17
 */
@Service
public class ScoreCalculationServiceImpl implements ScoreCalculationService {

    @Autowired
    private IndicatorTreeMapper indicatorTreeMapper;;

    @Autowired
    private RulesTypeLevelMapper rulesTypeLevelMapper;

    @Autowired
    private MetricDirectScoreMapper metricDirectScoreMapper;

    @Autowired
    private SortMethodMapper sortMethodMapper;

    @Autowired
    private RatioBandInfoMapper ratioBandInfoMapper;

    @Override
    public Integer selectionRule(String indexId, String periodTime, List<ScoreCalculationData> dataList) {
        //查询指标信息
        IndicatorTree indicatorTree = indicatorTreeMapper.selectOne(new LambdaQueryWrapperX<IndicatorTree>()
                .eq(IndicatorTree::getId, indexId)
                .eq(IndicatorTree::getYear, periodTime));
        if (null != indicatorTree){
            metricDirectScoreMapper.delete(new LambdaQueryWrapperX<MetricDirectScore>()
                    .eqIfPresent(MetricDirectScore :: getYear, periodTime)
                    .eqIfPresent(MetricDirectScore :: getIndicatorId, indexId));
            //根据指标配置的规则类型判断调用下列方法
            if (Objects.equals(indicatorTree.getType(), RulesTypeEnum.TYPE.getType())){
                return typeLevel(indicatorTree, periodTime, dataList);
            }
            if (Objects.equals(indicatorTree.getType(), RulesTypeEnum.SCORT.getType())){
                return sortRank(indicatorTree, periodTime, dataList);
            }
        }
        return 0;
    }


    @Override
    public Integer typeLevel(IndicatorTree indicator, String periodTime, List<ScoreCalculationData> dataList) {

                ArrayList<MetricDirectScore> addList = new ArrayList<>();
                if (CollectionUtil.isNotEmpty(dataList)) {
                    //查询规则，算出得分，并且存入数据库
            List<RulesTypeLevel> rulesList = rulesTypeLevelMapper.selectList(new LambdaQueryWrapperX<RulesTypeLevel>()
                    .eq(RulesTypeLevel::getIndexId, indicator.getId())
                    .eq(RulesTypeLevel::getPeriodTime, periodTime));
            //按照选项进行分类
            Map<String, List<RulesTypeLevel>> typeLevelMap = rulesList.stream().collect(Collectors.groupingBy(RulesTypeLevel::getTypeLevel));
            Map<String, List<ScoreCalculationData>> deptNameGroupMap = dataList.stream().filter(item -> item.getDeptName() != null).collect(Collectors.groupingBy(ScoreCalculationData::getDeptName));
            for (String deptName : deptNameGroupMap.keySet()) {
                //科室的得分项
                Double score = 0d;
                List<ScoreCalculationData> scoreCalculationDataList = deptNameGroupMap.get(deptName);
                HashMap<String, HashMap<String,Double>> groupScoreMap = new HashMap<>();
                for (ScoreCalculationData scoreCalculationData : scoreCalculationDataList) {
                    //读取这个类型的数据规则
                    List<RulesTypeLevel> rulesTypeLevel = typeLevelMap.get(scoreCalculationData.getType());
                    if (CollectionUtil.isNotEmpty(rulesTypeLevel)) {
                        RulesTypeLevel rules = rulesTypeLevel.get(0);
                        Long unitQuantity = rules.getNum();
                        if (null != unitQuantity && 0L != unitQuantity){
                            //计算本类型的得分
                            double typeScore = scoreCalculationData.getNum() / unitQuantity * rules.getScore();
                            if (null != rules.getMaxScore()) {
                                //控制类型的最大得分
                                if (typeScore >= rules.getMaxScore()) {
                                    typeScore = rules.getMaxScore();
                                }
                            }
                            String groupIds = rules.getGroupIds();
                            if (StringUtils.isNotEmpty(groupIds)) {
                                ////本次得分类型得分如果是组合得分。两项不超过最大分
                                HashMap<String, Double> scoreMap = groupScoreMap.get(groupIds);
                                if (null == scoreMap) {
                                    scoreMap = new HashMap<>();
                                    scoreMap.put("score", typeScore);
                                    scoreMap.put("maxScore", rules.getGroupScore());
                                    groupScoreMap.put(groupIds, scoreMap);

                                }else {
                                    scoreMap.put("score", typeScore + scoreMap.get("score"));
                                }
                                //到最后统一加组合得分,先给零不加
                                typeScore = 0;
                            }
                            score = typeScore + score;
                        }
                        //科室在这个指标中已经得分超过最大值。跳出规则循环，继续下一个科室循环，此时分组的得分还没加，但是对于最大值判断不影响
                        if (null != indicator.getScore()) {
                            if (score >= stringToDoubleOrNull(indicator.getScore())) {
                                score = stringToDoubleOrNull(indicator.getScore());
                                break;
                            }
                        }
                    }
                }
                //把前面组中的得分加上去,没分组自动不循环
                for (String groupIds : groupScoreMap.keySet()) {
                    HashMap<String, Double> scoreMap = groupScoreMap.get(groupIds);
                    if (scoreMap.get("score") > scoreMap.get("maxScore")) {
                        score = score + scoreMap.get("maxScore");
                    }else{
                        score = score + scoreMap.get("score");
                    }
                }
                MetricDirectScore metricDirectScore = new MetricDirectScore(indicator.getId(),
                        indicator.getIndicatorName(), null,
                        deptName, doubleToString(score), periodTime);
                addList.add(metricDirectScore);
            }
            if (addList.size() > 0) {
                metricDirectScoreMapper.insertBatch(addList);
                return addList.size();
            }
        }
        return 0;
    }

    public static String doubleToString(Double number) {
        if (number != null){
            DecimalFormat decimalFormat = new DecimalFormat("#0.000");
            return decimalFormat.format(number);
        }
        return "0";
    }

    /**
     *
     * @param indicator
     * @param periodTime
     * @param dataList  在导入完数据以后调用这个存分数 传入的数据一定是校验过环比、同比、本身数据的
     * @return
     */
    @Override
    public Integer sortRank(IndicatorTree indicator, String periodTime, List<ScoreCalculationData> dataList) {
        ArrayList<MetricDirectScore> addList = new ArrayList<>();
        //获取指标配置的排序规则
        List<SortMethod> ratioBandInfoList = sortMethodMapper.selectList(new LambdaQueryWrapperX<SortMethod>()
                .eq(SortMethod::getIndicatorId, indicator.getId())
                .eq(SortMethod::getPeriodTime, periodTime));
        //获取类型
        List<String> ksTypeList = ratioBandInfoList.stream().
                map(SortMethod::getKsType).distinct().collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(dataList)){
            for (String s : ksTypeList) {
                //筛选出对应的科室类型的数据【这里数据已经前面筛选过指标和年份了，所以只要筛选科室类型】
                List<ScoreCalculationData> scoreCalculationData = dataList.stream().
                        filter(data -> Objects.equals(data.getType(), s)).collect(Collectors.toList());
                //筛选出对应这个科室的规则【这里数据已经前面筛选过指标和年份了】
                List<SortMethod> sortMethodList = ratioBandInfoList.stream().
                        filter(sortMethod -> Objects.equals(sortMethod.getKsType(), s)
                        ).collect(Collectors.toList());
                    for (SortMethod sortMethod : sortMethodList) {
                        selectionSortRank(indicator,periodTime,sortMethod,scoreCalculationData);
                    }
            }
        }
        return 0;
    }
    /**
     * 获取已经过去的年份 传入-1即前一个年
     * @param date
     * @param oldNum
     * @return
     */
    public static String getOlYdYear(Date date,Integer oldNum){
        SimpleDateFormat format = new SimpleDateFormat("yyyy");
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.YEAR, oldNum);
        String start =format.format(c.getTime());
        return start;
    }

    /**
     *
     * @param
     * @param scoreCalculationData 科室数据
     * @return
     */
    public Integer selectionSortRank(IndicatorTree indicatorTree,String periodTime,SortMethod sortMethod, List<ScoreCalculationData> scoreCalculationData) {

       ArrayList<MetricDirectScore> metricDirectScores = new ArrayList<>();
        //参照(自身/同比/环比)
        String comparisonReferences = sortMethod.getComparisonReferences();
        //排序方式(倒序/升序)
        String sortStyle = sortMethod.getSortStyle();
        //个数（用作后续比对占比来用的）
        Double size = Double.valueOf(String.valueOf(scoreCalculationData.size()));
        //具体规则[通过指标规则id匹配与之相关的具体规则]
        List<RatioBandInfo> ratioBandInfos = ratioBandInfoMapper.selectList(new LambdaQueryWrapperX<RatioBandInfo>()
                .eq(RatioBandInfo::getIndicatorMethodId, indicatorTree.getId())
                .eq(RatioBandInfo::getPeriodTime, periodTime));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy"); // 设置日期时间格式
//        LocalDateTime dateTime = LocalDateTime.parse(periodTime, formatter); // 解析字符串为LocalDateTime对象

        //这里传入的同比/环比/本身数据都是一开始业务就已经判断好了的这里面只用管升序/降序
        if (Objects.equals(sortStyle, "升序")) {
            scoreCalculationData.sort(Comparator.comparing(ScoreCalculationData::getNum));
        } else {
            scoreCalculationData.sort(Comparator.comparing(ScoreCalculationData::getNum).reversed());
        }
        // 为每个元素分配rank【就是排序号】
        for (int i = 0; i < scoreCalculationData.size(); i++) {
            scoreCalculationData.get(i).setRank(i + 1); // 注意：这里从1开始计数，如果你想从0开始，则去掉+1
        }
        for (RatioBandInfo ratioBandInfo : ratioBandInfos) {
            Double startRatio = Double.valueOf(ratioBandInfo.getStartRatio())/100*size;
            Double endRatio = Double.valueOf(ratioBandInfo.getEndRatio())/100*size;
            for (ScoreCalculationData scoreCalculationDatum : scoreCalculationData) {

                //特殊方法
                if( sortMethod.getIsSpecialValue() !=null){

                }
                //正常规则
                if(scoreCalculationDatum.getRank()>=startRatio&&scoreCalculationDatum.getRank()<=endRatio){
                    MetricDirectScore metricDirectScore = new MetricDirectScore(indicatorTree.getId(),
                            indicatorTree.getIndicatorName(), null,
                    scoreCalculationDatum.getDeptName(), ratioBandInfo.getScore(), periodTime);
                    metricDirectScores.add(metricDirectScore);
                }
            }
        }
        if (metricDirectScores.size() > 0) {
             metricDirectScoreMapper.insertBatch(metricDirectScores);
        }
        return 1;
    }

    /**
     * 将字符串转换为Long类型，如果转换失败，返回0L
     * @param str
     * @return
     */
    public Double stringToDoubleOrNull(String str) {
        if (str == null) {
            return 0d;
        }
        try {
            return Double.valueOf(str);
        } catch (NumberFormatException e) {
            // 如果str不是有效的长整型数字字符串，可以选择抛出异常，或者返回一个默认值
            // 这里为了符合题目要求，我们直接返回0L
            return 0d;
        }
    }

}
